package com.springboot.common.resolver;

import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.ServletRequest;

/**
 * @Author: TongRui乀
 * @Date: 2020-04-12 16:56
 * @description：  自定义的参数解析器
 */
@Component
public class MyHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {


    /**
     *  支持使用@MyRequestParam注解修饰的参数
     * @param methodParameter
     * @return
     */
    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {

        MyRequestParam param = methodParameter.getParameterAnnotation(MyRequestParam.class);

        return param != null;
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

        // 获取目标参数类型
        Class<?> realClass = parameter.getParameterType();

        if (!ClassUtils.isAssignable(parameter.getParameterType(), realClass)) {
            throw new IllegalStateException("MyRequestParam real class [ " + parameter.getParameterName() + " ] not cast [ " + parameter.getParameterType().getName() + " ]");
        }
        // 创建实例
        Object obj = realClass.newInstance();
        // 是用WebDataBinder绑定参数到类型
        // spring本身就有一个很方便的参数绑定机制，直接使用就可以很方便的实现参数注入
        // createBinder中的第三个参数还不知道作用是什么，知道读者可以给我解释一下
        WebDataBinder binder = binderFactory.createBinder(webRequest, obj, parameter.getParameterName());
        ServletRequest servletRequest = webRequest.getNativeRequest(ServletRequest.class);
        Assert.state(servletRequest != null, "No ServletRequest");

        ServletRequestDataBinder servletBinder = (ServletRequestDataBinder) binder;
        // 参数解析在这
        servletBinder.bind(servletRequest);
        return obj;
    }
}
